#![allow(dead_code)]

use crate::entity::{prelude::*, stock_order};
use sea_orm::{
    prelude::*,
    sea_query::{Cond, Expr},
    *,
};
use serde::{Deserialize, Serialize};

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct OrderSearch {
    uid: Option<i32>,
    stock_code: Option<String>,
    status: Option<i32>,
    pageindex: u64,
    pagesize: u64,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct AddOrder {
    pub stock_code: String,
    pub trading_number: i32,
    pub price: f64,
    pub uid: i32,
}

pub async fn get_by_stockcode(
    db: &DbConn,
    stock_code: &str,
    price: f64,
) -> Result<Vec<stock_order::Model>, DbErr> {
    let cond = Cond::all()
        .add(stock_order::Column::StockCode.eq(stock_code))
        .add(stock_order::Column::Price.lte(price))
        .add(stock_order::Column::Status.eq(0));

    StockOrder::find().filter(cond).all(db).await
}

pub async fn get_by_id(
    db: &DbConn,
    uid: i32,
    oid: i32,
) -> Result<Option<stock_order::Model>, DbErr> {
    StockOrder::find()
        .filter(
            Cond::all()
                .add(Expr::col(stock_order::Column::Uid).eq(uid))
                .add(Expr::col(stock_order::Column::Id).eq(oid))
                .add(Expr::col(stock_order::Column::Status).eq(0)),
        )
        .one(db)
        .await
}
pub async fn get_by_status(db: &DbConn, status: i32) -> Result<Vec<stock_order::Model>, DbErr> {
    StockOrder::find()
        .filter(stock_order::Column::Status.eq(status))
        .all(db)
        .await
}

pub async fn get_page(
    db: &DbConn,
    search: OrderSearch,
) -> Result<(Vec<stock_order::Model>, u64), DbErr> {
    let mut query = StockOrder::find();

    query = match search.uid {
        Some(value) => query.filter(stock_order::Column::Id.eq(value)),
        None => query,
    };

    query = match search.stock_code {
        Some(value) => query.filter(stock_order::Column::StockCode.contains(&value)),
        None => query,
    };

    query = match search.status {
        Some(value) => query.filter(stock_order::Column::Status.eq(value)),
        None => query,
    };

    let page: Paginator<DatabaseConnection, SelectModel<stock_order::Model>> = query
        .order_by_desc(stock_order::Column::TradingTime)
        .paginate(db, search.pagesize);

    let num_pages = page.num_pages().await?;
    page.fetch_page(search.pageindex - 1)
        .await
        .map(|p| (p, num_pages))
}

pub async fn get_only(db: &DbConn, id: i32) -> Result<Option<stock_order::Model>, DbErr> {
    StockOrder::find_by_id(id).one(db).await
}

pub async fn add(
    db: &DbConn,
    model: AddOrder,
) -> Result<InsertResult<stock_order::ActiveModel>, DbErr> {
    let entity = stock_order::ActiveModel {
        stock_code: Set(model.stock_code),
        status: Set(0), //-2撤销、-1失败、0委托、1成交
        trading_number: Set(model.trading_number),
        price: Set(Decimal::from_f64_retain(model.price).unwrap()),
        uid: Set(model.uid),
        ..Default::default()
    };

    StockOrder::insert(entity).exec(db).await
}

pub async fn update_status(
    db: &DbConn,
    oid: i32,
    uid: i32,
    status: i32,
) -> Result<UpdateResult, DbErr> {
    StockOrder::update_many()
        .col_expr(stock_order::Column::Status, Expr::value(status))
        .filter(
            Cond::all()
                .add(stock_order::Column::Id.eq(oid))
                .add(stock_order::Column::Uid.eq(uid)),
        )
        .exec(db)
        .await
}

pub async fn delete(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
    StockOrder::delete_by_id(id).exec(db).await
}
